<?php
/*
 * @Description: 
 */
/*
 * @Description: 用户模块
 */

namespace app\controller;

use app\BaseController;
use think\exception\ValidateException;
use think\facade\Db;

class UserBak extends BaseController
{
  public function index()
  {
    // 根据不同的action返回不同的内容
    $action = $this->request->action();
    // 获取应用基础路径
    $path = $this->app->getBasePath();
    // index - D:\code\www.tp.com\app\
    return $action . ' - ' . $path;
    // 根据不同的action返回不同的内容
    // return 'user index';
  }

  public function register()
  {
    try {
      $this->validate([
        'username' => 'require|alpha',
        'password' => 'require|alpha',
        'email' => 'require|email',
      ], 'app\controller\HelloWord',);
      //code...
    } catch (ValidateException $e) {
      dump($e->getError());
      // 验证失败，返回错误信息
      // return json(['code' => 0, 'msg' => $th->getMessage()]);
    }
  }

  public function login()
  {
    return '用户登录';
  }
  public function get()
  {
    // 链接数据库表，查询
    $sqlinfo = Db::name('user')->select();
    // 获取单条数据
    // $user = Db::table('user')->where('id', 1)->find();
    // 查询没有数据,返回空对象
    // $user = Db::table('user')->where('id', 1)->findOrEmpty();
    // 查询没有数据异常抛出异常
    // $user = Db::table('user')->where('id', 21321)->findOrFail();
    halt($sqlinfo); // 输出数据,调试使用,返回json数据,返回数据集

    // 获取所有数据,返回数组
    $userarray = Db::name('user')->select()->toArray();
    // 获取单条数据,返回数组
    halt($userarray); // 输出数据,调试使用,返回json数据,返回数组
    // 返回json数据

    return json($user);
  }

  public function select()
  {
    // 如果设置了数据表前缀参数的话，可以使用
    // Db::name('user')->where('id', 1)->find();
    // Db::name('user')->where('status', 1)->select();
    // 如果你的数据表没有设置表前缀的话，那么name和table方法效果一致。
    $user = Db::name('user')->select();
    // 查询某个字段的值可以用-返回某个字段的值
    $user = Db::name('user')->where('id', 1)->value('name');

    // 查询某一列的值可以用
    // 返回数组
    $user = Db::name('user')->where('id', 1)->column('name');
    // 指定id字段的值作为索引
    $user = Db::name('user')->where('id', 1)->column('name', 'id');
    // 如果要返回完整数据，并且添加一个索引值的话，可以使用
    $user = Db::name('user')->where('id', 1)->column('*', 'id');

    //数据分批处理
    // 如果你需要处理成千上百条数据库记录，可以考虑使用chunk方法，该方法一次获取结果集的一小块，然后填充每一小块数据到要处理的闭包，该方法在编写处理大量数据库记录的时候非常有用。
    // 例如，你可以使用chunk方法来处理所有用户的记录，每次处理100条记录：
    Db::name('user')->chunk(2, function ($items) {
      foreach ($items as $user) {
        // dump($user); // 输出每个用户记录
        // 处理每个用户记录
      }
    });

    /* * 游标查询: 为了解决内存开销，每次读取一行，并返回到下一行再读取
    如果你需要处理大量的数据，可以使用新版提供的游标查询功能，该查询方式利用了PHP的生成器特性，可以大幅减少大量数据查询的内存开销问题。

    如果你需要处理大量的数据，可以使用新版提供的游标查询功能，该查询方式利用了PHP的生成器特性，可以大幅减少大量数据查询的内存开销问题。
    例如，你可以使用cursor方法来处理所有用户的记录，每次处理一条记录：
     */
    $cursor = Db::name('user')->cursor();
    foreach ($cursor as $user) {
      dump($user['name']); // 输出每个用户记录
      // 处理每个用户记录
    }

    return Db::getLastSql(); // 返回最后执行的SQL语句
    // return json($user);
  }
  // 查询数据-添加
  public function insert()
  // 使用 **insert()** 方法可以向数据表添加一条数据，更多的字段采用默认；
  {
    // 插入数据
    $data = [
      'name' => 'testuser',
      'age' => 22,
      'gender' => '男',
      'details' => '测试',
    ];
    $result = Db::name('user')->insert($data);


    // 如果想强行新增抛弃不存在的字段数据，则使用 **strick(false)** 方法，忽略异常；
    $data = [
      'name' => 'testuser',
      'age' => 22,
      'gender' => '男',
    ];
    $result = Db::name('user')->strict(false)->insert($data);

    // - 如果我们采用的数据库是 mysql，可以支持 **replace** 写入；
    // - insert 和 replace insert 写入的区别，前者表示表中存在主键相同则报错，后者则修改；
    $data = [
      'name' => 'testuser',
      'age' => 22,
      'gender' => '男',
      'details' => '测试2',
    ];
    $result = Db::name('user')->replace()->insert($data);

    // 使用 **insertGetId()** 方法，可以在新增成功后返回当前数据 ID；
    $id = Db::name('user')->insertGetId($data);

    // 使用 **insertAll()** 方法，可以批量新增数据，但要保持数组结构一致；
    $data = [
      [
        'name' => 'testuser',
        'age' => 22,
        'gender' => '男',
        'details' => '测试2',
      ],
      [
        'name' => 'testuser2',
        'age' => 23,
        'gender' => '女',
        'details' => '测试3',
      ],
    ];
    $result = Db::name('user')->insertAll($data);

    if ($result) {
      echo '数据插入成功';
    } else {
      echo '数据插入失败';
    }

    // 返回最后执行的SQL语句
    return Db::getLastSql();
  }
  // 查询数据-更新
  public function update()
  {
    // 更新数据
    $data = [
      'name' => 'updateduser',
      'age' => 25
    ];
    // 使用 **update()** 方法来修改数据，修改成功返回影响行数，没有修改返回 **0**；
    $result = Db::name('user')->where('id', 1)->update($data);

    // 如果修改数据包含了主键信息，比如 id，那么可以省略掉 where 条件；
    $data = [
      'id' => 1,
      'name' => 'updateduser',
      'age' => 25
    ];
    $result = Db::name('user')->update($data);

    // 如果想让一些字段修改时执行 SQL 函数操作，可以使用 **exp()** 方法实现；
    $result = Db::name('user')->exp('age', 'age+3')->where('id', 1)->update();
    // 派生自字段，延迟执行，毫秒
    // setInc("age", 1, 600)
    // setDec("age", 2, 600)

    // 使用Db::raw 更加清晰灵活
    $result = Db::name('user')->where('id', 2)->update([
      'details' => Db::raw('UPPER(details)'), // 使用 Db::raw 来执行原生 SQL 表达式，变更 details 字段为大写
      'age' => Db::raw('age + 1') // 使用 Db::raw 来执行原生 SQL 表达式，将 age 字段加 1
    ],); // 指定更新条件
    // **save()** 方法是一个通用方法，可以自行判断是新增还是修改(更新)数据；
    //  包含主键，即修改；否则，新增
    $result = Db::name('user')->where('id', 2)->save($data);

    return Db::getLastSql(); // 返回最后执行的SQL语句
  }

  // 查询数据-删除
  public function delete()
  {
    // 删除数据
    // 使用 **delete()** 方法来删除数据，删除成功返回影响行数，没有删除返回 **0**；
    $result = Db::name('user')->where('id', 137)->delete();

    // // 如果想删除多条数据，可以使用 **whereIn()** 方法；
    // $result = Db::name('user')->whereIn('id', [2, 3])->delete();

    // // 如果想删除所有数据，可以使用 **truncate()** 方法；
    // $result = Db::name('user')->truncate();

    return Db::getLastSql(); // 返回最后执行的SQL语句
  }

  // 查询数据-表达式查询
  public function expFn()
  {
    // where("字段名","查询表达式","查询条件");
    // 查询id大于等于2且小于等于5的数据
    $result = Db::name('user')->where('id', '>=', 2)->where('id', '<=', 5)->select();

    // 查询姓王的用户
    $result = Db::name('user')->where('name', 'like', '王%')->select();
    // 快捷键
    // 查询姓王的用户
    $result = Db::name('user')->whereLike('name', '王%')->select();

    // 查询年龄在20-30之间的用户
    $result = Db::name('user')->where('age', 'between', [20, 30])->select();
    // 快捷键
    $result = Db::name('user')->whereBetween('age', [20, 30])->select();

    // 查询年龄不在20-30之间的用户
    $result = Db::name('user')->where('age', 'not between', [20, 30])->select();
    // 快捷键
    $result = Db::name('user')->whereNotBetween('age', [20, 30])->select();

    // 查询not null的用户
    $result = Db::name('user')->where('details', 'not null')->select();
    // 快捷键
    $result = Db::name('user')->whereNotNull('details')->select();

    // exp查询，自定义sql表达式
    $result = Db::name('user')->where('id', 'exp', '<> 8 and id >5')->select();
    // 快捷键
    $result = Db::name('user')->whereExp('id', '<> 8 and id >5')->select();
    // - 这里推荐：有快捷方式的用快捷方式，通过Ctrl+方法名得知，快捷方式绕过了很多拼装流程，速度更快；
    return Db::getLastSql();
  }

  // 查询数据- 超多条件查询
  public function whereFn()
  {
    // 1. 字符串条件
    $result = Db::name('user')->whereRaw('name like "%王%"')->select();

    // 包含变量的多条件查询：
    $age = 25;
    $name = '王';
    $gender = '男';
    // 预处理机制
    $result = Db::name('user')->whereRaw(
      "name like '%{$name}%' and age > {$age}",
    )->select();
    // 2. 数组条件
    $result = Db::name("user")->whereRaw("age>:age AND gender=:gender", [
      "age"       => $age,
      "gender"    => $gender
    ])->select();

    // 使用 **field()** 方法，可以指定要查询的字段；
    $result = Db::name('user')->field(['id', 'name'])->select();
    // 使用 **field()** 方法，给指定的字段设置别名；
    $result = Db::name('user')->field(['id', 'name', 'age as cy_age'])->select();
    // 在 **fieldRaw()** 方法里，可以直接给字段设置 MySQL 函数；
    $result = Db::name("user")->fieldRaw("id, UPPER(details)")->select();
    $result = Db::name("user")->field(true)->select();   // 推荐
    // 使用 **distinct()** 方法，可以去除重复数据；
    $result = Db::name("user")->withoutField("details")->select();
    $data = [
      'name' => 'testuser',
      'age' => 22,
      'gender' => '男',
    ];
    Db::name("user")->field("name,age,gender")->insert($data);
    echo $result;
    // // 换行
    echo "<br>";
    return Db::getLastSql();
  }

  // 常用链式方式
  public function chain()
  {
    // 给数据库起个别名
    // Db::name("user")->alias("a")->select();
    // return Db::getLastSql();

    // // 起别名最主要是和另一张表进行关联，这里看手册好了，没表测试
    // alias("a")->join()->where("a.id", "=", "b.id")->select();

    // 使用 **limit()** 方法，限制获取输出数据的个数；
    $result = Db::name('user')->limit(2)->select();

    // 使用 **limit()** 方法，限制获取输出数据的个数；
    $result = Db::name('user')->limit(2, 5)->select(); // 从第3条开始，获取2条数据
    $result = Db::name('user')->page(1, 5)->select(); // 获取第1页，每页5条数据

    // 使用 **order()** 方法，可以指定排序方式，没有指定第二参数，默认 asc；
    $result = Db::name('user')->order('age', 'desc')->select();

    // 支持数组的方式，对多个字段进行排序；
    $result = Db::name('user')->order(['age' => 'desc', 'id' => 'asc'])->select();

    // 使用 **group()** 方法，给性别不同的人进行 age 字段的总和统计；
    $result = Db::name('user')->fieldRaw("gender, sum(age) as total")->group("gender")->select();

    // 使用 **group()** 分组之后，再使用 **having()** 进行筛选；
    // 统计性别的年龄总和，筛选大于100的
    $result = Db::name('user')->fieldRaw("gender, sum(age) as total")->group("gender")->having("total > 100")->select();
    echo $result;
    echo "<br>";
    return Db::getLastSql();
  }
  // 时间查询
  public function timeFn()
  {
    // 传统时间筛选
    $result = Db::name("user")->where("create_time", ">", "2022-1-1")->select();
    $result = Db::name("user")->where("create_time", "between", ["2020-1-1", "2023-1-1"])->select();
    // 时间查询
    $result = Db::name("user")->where("create_time", "between time", ["2020-1-1", "2023-1-1"])->select();

    // 使用快捷方式查询
    $result = Db::name("user")->whereTime("create_time", ">=", "2022-1-1")->select();

    // 默认是 > 可以省略
    $result = Db::name("user")->whereTime("create_time", "2022-1-1")->select();

    // 区间查询，包含 whereNotBetweenTime
    $result = Db::name("user")->whereBetweenTime("create_time", "2020-1-1", "2023-1-1")->select();

    // 使用 **whereYear** 查询今年的数据、去年的数据和某一年的数据；
    // 查询今年
    $result = Db::name("user")->whereYear("create_time")->select();
    // 查询去年
    $result = Db::name("user")->whereYear("create_time", "last year")->select();
    // 查询某一年
    $result = Db::name("user")->whereYear("create_time", "2019")->select();

    // 查询指定时间的数据，比如两小时内的；
    // 两小时内的
    $result = Db::name("user")->whereTime("create_time", "-2 hours")->select();

    // 查询两个时间字段时间有效期的数据，比如活动开始到结束的期间；
    // 比如创建两个字段：start_time，end_time，注册后，分别写入对应时间表明它的有效期；
    // 直接这么写，不太好理解，看手册的另一种普通写法很容易理解
    // 实战中，字段丰富的时候再演示
    $result = Db::name("user")->whereBetweenTimeField("start_time", "end_time")->select();
    // 普通写法
    $result = Db::name("user")->where("start_time", "<=", time())->where("end_time", ">=", time())->select();

    echo $result;
    echo "<br>";
    return Db::getLastSql();
  }
  // 聚合查询
  public function aggFn()
  {
    // 使用 **count()** 方法，可以求出所查询数据的数量；
    $result = Db::name("user")->count();
    // 使用 **max()** 方法，可以求出所查询数据的最大值；
    $result = Db::name("user")->max("id");
    // 使用 **min()** 方法，可以求出所查询数据的最小值；
    $result = Db::name("user")->min("id");
    // 使用 **avg()** 方法，可以求出所查询数据的平均值；
    $result = Db::name("user")->avg("id");
    // 使用 **sum()** 方法，可以求出所查询数据的总和；
    $result = Db::name("user")->sum("id");

    echo $result;
    echo "<br>";
    return Db::getLastSql();
  }
  // 子查询
  public function subFn()
  {
    // 使用 **fetchSql()** 方法，传递参数true时，可以设置不执行 SQL，直接返回SQL语句；
    $result = Db::name("user")->where("id", ">", 1)->fetchSql(true)->select();

    // 使用 **buildSql()** 方法，也是返回 SQL 语句，不需要再执行 select()，且有括号；
    $result = Db::name("user")->buildSql(true);

    // 子查询样式
    $subQuery = Db::name("user")->field("id")->where("age", ">", 18)->buildSql();
    $user = Db::name("user")->whereExp("id", "IN " . $subQuery)->select();

    // 采用闭包构建子查询
    $user = Db::name("user")->where("id", "IN", function ($query) {
      $query->name("user")->field("id")->where("age", ">", 18);
    })->select();
    echo $result;
    echo "<br>";
    return Db::getLastSql();
  }

  // 原生查询
  public function rawFn()
  {
    $result = Db::name("user")->raw("select * from user where id = 1")->select();
    // 条件判断
    $user = Db::name("user")->when(false, function ($query) {
      // 满足条件执行这段SQL
      $query->where("id", ">", 5);
    }, function ($query) {
      // 不满足条件执行这段SQL
      $query->where("id", "<=", 5);
    })->select();

    echo $result;
    echo "<br>";
    return Db::getLastSql();
  }

  // 事务
  public function transFn()
  {
    // - 数据库的表引擎需要是 InnoDB 才可以使用，如果不是调整即可；
    // - 事务处理，需要执行多个 SQL 查询，数据是关联恒定的；
    // - 如果成功一条查询，改变了数据，而后一条失败，则前面的数据回滚；
    // - 比如：银行取钱，银行ATM扣了1000，但入口被卡住，你没拿到，这时需要事务处理；
    // - 系统提供了两种事务处理的方式，第一种是自动处理，出错自动回滚；
    // - 第二种是手动处理，需要手动提交或回滚；
    // 出现异常回滚
    Db::transaction(function () {
      Db::name("user")->delete(12);
      Db::name("user")->findOrFail(13);
    });

    // 手动处理，基本和原生处理类似，可以自行输出错误信息；
    // 启动事务
    Db::startTrans();
    try {
      Db::name("user")->delete(12);
      Db::name("user")->findOrFail(13);
      //提交事务
      Db::commit();
    } catch (\Exception $e) {
      echo "执行SQL失败！";
      // 回滚
      Db::rollback();
    }
  }

  // 获取器
  public function getFn()
  {
    // 获取器的意思就是：将数据的字段进行转换处理再进行操作；
    // 比如在获取数据列表的时候，将获取到的详情字段全部大写；
    // 获取器改变字段值
    $user = Db::name("user")->withAttr("details", function ($value, $data) {
      // NULL 不处理
      if ($value != null) {
        return strtoupper($value);
      }
    })->select();
  }

  // 关联索引查询 - 索引查询
  public function indexFn()
  {
    // 性别男，年龄大于15岁，常规做法
    $user = Db::name("user")->where("age", ">", 15)
      ->where("gender", "男")->select();

    // 索引数组方式，二维数组，返回的SQL 是一条 AND 并列关系
    $user = Db::name("user")->where([
      ["age", ">", "15"],
      ["gender", "=", "男"]
    ])->select();

    // 如果是等于，可以直接用关联数组，一维
    $user = Db::name("user")->where([
      "age"     =>  15,
      "gender"  =>  "男"
    ])->select();

    // 两种模式结合起来，
    $user = Db::name("user")->where([
      ["age", ">", "15"],
      "gender"  =>  "男"
    ])->select();

    // 搜索条件独立管理，这里=号写全
    $map[] = ["age", ">", "15"];
    $map[] = ["gender", "=", "男"];

    $user = Db::name("user")->where($map)->select();
  }

  // 拼装查询条件
  public function mapFn()
  {
    $map = [];
    $map[] = ["age", ">", "15"];
    $map[] = ["gender", "=", "男"];
    $user = Db::name("user")->where($map)->select();

    // or和and 拼装查询
    // 使用 **|(OR)** 或 **&(AND)** 来实现 where 条件的高级查询，where 支持多个连缀；
    $user = Db::name("user")->where("name|details", "like", "%王%")
      ->where("id&create_time", ">", 0)
      ->select();

    // 索引数组方式，可以在 where 进行多个字段进行查询；
    // 索引数组拼装
    $user = Db::name("user")->where([
      ["id", ">", "5"],
      ["gender", "=", "女"],
      ["age", "<=", 15],
      ["details", "like", "%我%"]
    ])->select();

    // exp 拼装
    $user = Db::name("user")->where([
      ["gender", "=", "男"],
      ["age", "exp", Db::raw(">=10 AND id<5")]
    ])->select();

    // 如果有多个where，并需要控制优先级，那么在可以在需要的部分加上中括号
    // 下面的代码无法控制优先级
    $user = Db::name("user")->where([
      ["gender", "=", "男"],
      ["age", "exp", Db::raw(">=10 AND id<5")]
    ])->where("details", "like", "%我%")->select();

    // // 外加一个中括号
    // ->where([[
    //     ...
    // ]])

  }
}
